#include <scheme.h>

#include "config.h"
#include "audit_list.h"


LIST_HEAD g_auditList;
static spinlock_t g_audit_lock;
static atomic_t g_auditCount = ATOMIC_INIT(0);

void destroy_audit_item(AUDIT_ITEM * item)
{
	if(item->msg){
		kfree(item->msg);
	}	
	kfree(item);
	return;
}

AUDIT_ITEM * create_audit_item(void)
{
	AUDIT_ITEM * item = NULL;
	
	item = (AUDIT_ITEM * )kmalloc(sizeof(AUDIT_ITEM), GFP_KERNEL);
	if(item){
		memset(item, 0, sizeof(AUDIT_ITEM));
	}	
	return item;
}

ADT_COMMON * create_audit_msg(int cntLen, unsigned int adtType)
{
	unsigned int total = cntLen + sizeof(ADT_COMMON);
	ADT_COMMON * msg = (ADT_COMMON *)kmalloc(total, GFP_KERNEL);
	
	if(!msg) return NULL;
	
	msg->hdr.length = total;
	msg->hdr.type = adtType;
	msg->hdr.magic = __ADT_MAGIC;
		
	return msg;
}

int audit_list_push_file_operation(const char * fileName, int opType, int uid)
{
	int retval = -1;
	ADT_COMMON * msg = NULL;
	int cntLen = sizeof(ADT_FILE_EVENT) + strlen(fileName);
	ADT_FILE_EVENT * evt;
	AUDIT_ITEM * item  = NULL;
	
	msg = create_audit_msg(cntLen, __ADT_TYPE_FILE);
	if(!msg) goto DONE;
	
	evt = (ADT_FILE_EVENT *)&msg->cnt[0];
	evt->nameLen = strlen(fileName) + 1;
	evt->opType = opType;
	evt->uid = uid;
	strcpy(evt->fileName, fileName);
	item = create_audit_item();
	if(!item){
		kfree(msg);
		msg = NULL;
		goto DONE;
	}
	item->msg = msg;
	audit_list_insert(item);
	
	retval = 0;
DONE:
	return retval;
}

int audit_list_insert(AUDIT_ITEM * item)
{
	if(atomic_read(&g_auditCount) > MAX_AUDIT_LIST_COUNT){
		destroy_audit_item(item);
		return -1;
	}
	
	spin_lock(&g_audit_lock);	
	
	atomic_inc_return(&g_auditCount);
	__list_add_tail(&g_auditList, &item->head);
	
	spin_unlock(&g_audit_lock);	
	return 0;
}

AUDIT_ITEM * audit_list_shift(void)
{
	AUDIT_ITEM * item = NULL;
	
	spin_lock(&g_audit_lock);	
	
	if(!__list_is_empty(&g_auditList)){
		LIST_HEAD * entry;
		atomic_dec_return(&g_auditCount);
		__list_remove_head(&g_auditList, entry);
		item = OBJECT_PTR(entry, AUDIT_ITEM, head);
	}
	spin_unlock(&g_audit_lock);		
	return item;
}

int audit_list_unshift(AUDIT_ITEM * item)
{
	if(atomic_read(&g_auditCount) > MAX_AUDIT_LIST_COUNT){
		destroy_audit_item(item);
		return -1;
	}
	
	spin_lock(&g_audit_lock);	
	
	atomic_inc_return(&g_auditCount);
	__list_add_head(&g_auditList, &item->head);
	
	spin_unlock(&g_audit_lock);	
	return 0;	
}

int read_audit(char * outBuffer, unsigned int len, unsigned int * pOutLen)
{
	int ntStatus = 0;
	int length = 0;
	int count = 0;
	long outputBufferLength = 0;
 
	unsigned char * outPtr = NULL;
	long left;  
	
	* pOutLen = 0;
	
	outputBufferLength = len;
	left = outputBufferLength;
	outPtr = (unsigned char *)outBuffer; 
	if(!outPtr) goto DONE;	  
	while(left > 0){
		ADT_COMMON * common;
		AUDIT_ITEM * item = NULL; 
		item = audit_list_shift();
		if(!item) break;		
		
		common = item->msg;
		if(common->hdr.length > left){
			audit_list_unshift(item);
			item = NULL;
			break;
		}
		
		count ++;
		
		// -- hdr = (AUDIT_COMMON_HDR *)(((unsigned char *)common) + sizeof(AUDIT_COMMON));
	 
		memcpy(outPtr, common, common->hdr.length);
	 
		left -= common->hdr.length;
		outPtr += common->hdr.length;
		length += common->hdr.length;
		
		destroy_audit_item(item);
	}
 
DONE: 
 
	* pOutLen = length;	
	return ntStatus;
}	
 
void audit_list_module_destroy(void)
{
	LIST_HEAD * entry;
	// -- __list_init(&g_auditList);
	
	spin_lock(&g_audit_lock);	
	while(!__list_is_empty(&g_auditList)){
		AUDIT_ITEM * item;
		__list_remove_head(&g_auditList, entry);
		item = OBJECT_PTR(entry, AUDIT_ITEM, head);
		destroy_audit_item(item);
		atomic_dec_return(&g_auditCount);
	}
	spin_unlock(&g_audit_lock);	
	return ;
}

int audit_list_module_init(void)
{
	__list_init(&g_auditList);
	spin_lock_init(&g_audit_lock);
	return 0;
}




